#include "TcpServer.h"

std::unique_ptr<AsyncLogger::AsyncLogger> g_logger(new AsyncLogger::AsyncLogger("./", "TcpServer", 1024 * 1024 * 1024, false));

void asyncLog(const char *logline, int len)
{
	printf("%s\n", logline);
	g_logger->append(logline, len);
	g_logger->append("\n", 1);
}

TcpServer::TcpServer(const std::string &ip, int port, int backlog)
    : listenAddr_(ip, port),
    started_(false)
{
  // todo: 初始化日志系统，用起来还是有点复杂，日志系统还是得改善才行。。。。。。
  AsyncLogger::Logger::setLogLevel(AsyncLogger::LogLevel::TRACE);
  AsyncLogger::Logger::setOutput(asyncLog);
  g_logger->start();

  // 创建event_base
#ifdef _WIN32
  WSADATA wsa_data;
  WSAStartup(0x0201, &wsa_data);
  evthread_use_windows_threads(); // 该函数需要在创建base之前调用，所以将base创建放在构造函数
#else
  evthread_use_pthreads();
#endif                            // WIN32
  base_ = event_base_new();
  assert(base_);

  sockaddr_in addr = listenAddr_.getSockAddr();
  // 创建listener
  listener_ = std::unique_ptr<evconnlistener, std::function<void(evconnlistener *)>>(
       evconnlistener_new_bind(
          base_,
          static_cast<evconnlistener_cb>([](evconnlistener *listener, socket_t sockfd, sockaddr *addr, int socklen, void *arg)->void
          {
            TcpServer *pthis = static_cast<TcpServer *>(arg);
            pthis->listenCallback(listener, sockfd, addr, socklen, arg);
          }),
          this, LEV_OPT_REUSEABLE | LEV_OPT_CLOSE_ON_FREE,
          backlog, (struct sockaddr *)&addr, sizeof(addr)),
      [](evconnlistener *listener)
      { evconnlistener_free(listener); });
}

TcpServer::~TcpServer()
{
}

bool TcpServer::Start(int eventbaseSize)
{
  eventbasePool_ = std::make_unique<EventbasePool>();
  eventbasePool_->start(eventbaseSize);
  started_ = true;
  event_base_dispatch(base_);
  return true;
}

void TcpServer::closeConnectionCallback(const std::shared_ptr<TcpConnection> &conn)
{
  std::lock_guard<std::mutex> lock(connMapLock_);
  connMap_.erase(conn->name());
  if (closeCallback_) {
	  closeCallback_(conn);
  }
}

void TcpServer::onMessageCallback(const std::shared_ptr<TcpConnection>& conn, Buffer& inBuffer)
{
	// do something
	if (messageCallback_) {
		messageCallback_(conn, inBuffer);
	}
}

void TcpServer::onWriteCompleteCallback(const std::shared_ptr<TcpConnection>& conn)
{
	// do something
	if (writeCompleteCallback_) {
		writeCompleteCallback_(conn);
	}
}

void TcpServer::Stop()
{
  started_ = false;
  event_base_loopbreak(base_);
}

void TcpServer::listenCallback(evconnlistener* listener, socket_t sockfd, sockaddr* addr, int socklen, void* arg)
{
	TcpServer* pthis = static_cast<TcpServer*>(arg);
	evutil_make_socket_nonblocking(sockfd);
	auto base = eventbasePool_->getNextBase().get();
	ConnectTask* task = new ConnectTask;
	task->base_ = base;
	task->server_ = pthis;
	task->socket_ = new Socket(sockfd); // note: 调用connectionEstanblish后交给TcpConnection的智能指针管理
	// note: 使用event_base_once可以将事件发送给event_base的事件循环的队列。从而实现在event_base的loop的线程中处理该事件，避免多个线程竞争event_base
	event_base_once(base, sockfd, EV_TIMEOUT,
		static_cast<event_callback_fn>([](socket_t sockfd, short event, void* arg) {
			ConnectTask* pTask = reinterpret_cast<ConnectTask*>(arg);
			pTask->server_->connectionEstanblish(sockfd, event, arg);
			}), task, nullptr);
	// todo: 使用一个pipe唤醒event_base的事件循环，这里使用了超时事件代替，更简单
}

void TcpServer::connectionEstanblish(ev_socklen_t sockfd, int event, void* arg)
{
	ConnectTask* task = reinterpret_cast<ConnectTask*>(arg);
	// 创建TcpConnection
	std::shared_ptr<TcpConnection> conn = std::make_shared<TcpConnection>(task->base_, task->socket_, true);
	// note: 设置TcpConnection的回调函数
	conn->setCloseCallback(std::bind(&TcpServer::closeConnectionCallback, this, std::placeholders::_1));
	conn->setMessageCallback(std::bind(&TcpServer::onMessageCallback,this,std::placeholders::_1,std::placeholders::_2));
	conn->setWriteCompleteCallback(std::bind(&TcpServer::onWriteCompleteCallback,this,std::placeholders::_1));
	//conn->se(server->getCloseConnectionCallback());
	delete task;

	// note: 对于加锁的顺序，默认先加TcpServer的锁，再执行回调函数，回调函数中可能会调用外部对象的锁（可能后续会改成TcpServer的锁解锁后才调用回调）
	std::lock_guard<std::mutex> lock(connMapLock_);
	connMap_[conn->name()] = conn;
	// note: 调用回调，由外部传入，方便封装TCPServer时外部类管理Connection
	if (connectionCallback_) {
		connectionCallback_(conn);
	}
	LOG_DEBUG << "accept new cmd connection: " << conn->name();
}